package com.example.volunteer.service.impl;


import com.example.volunteer.exception.CustomException;
import com.example.volunteer.mapper.ActivityMapper;
import com.example.volunteer.mapper.ApplyMapper;
import com.example.volunteer.mapper.PointsMapper;
import com.example.volunteer.model.Activity;
import com.example.volunteer.model.Apply;
import com.example.volunteer.model.Points;
import com.example.volunteer.service.ApplyService;
import com.example.volunteer.service.FileStorageService;
import com.example.volunteer.service.NotificationService;
import com.example.volunteer.util.PageResult;
import com.example.volunteer.util.QRCodeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class ApplyServiceImpl implements ApplyService {

    @Autowired
    private ApplyMapper applyMapper;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private QRCodeUtil qrCodeUtil;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private NotificationService notificationService;

    private static final Logger logger = LoggerFactory.getLogger(ApplyServiceImpl.class);

    @Autowired
    private PointsMapper pointsMapper;

    @Override
    @Transactional
    public void applyActivity(Integer activityId, String volunteerId) {
        if (applyMapper.findByActivityAndVolunteer(activityId, volunteerId) != null) {
            throw new CustomException("你已经参加了这个活动，无需重复报名");
        }

        if (!checkActivityLimit(volunteerId)) {
            throw new CustomException("你只能参加3个活动");
        }
        Activity activity = activityMapper.findById(activityId);
        if (activity == null) {
            throw new CustomException("活动不存在");
        }
        Double hours = (activity.getVolunteerHours())*10; // 调用目标方法

        int pointsEarned = hours.intValue(); // 转换为整数积分

        Points points = new Points();
        points.setVolunteerId(volunteerId);
        points.setActivityId(activityId);
        points.setPointsEarned(pointsEarned); // 使用setter避免构造函数顺序问题

        pointsMapper.insert(points);

        String qrContent = activityId + "-" + volunteerId;
        byte[] qrCodeBytes;
        try {
            qrCodeBytes = qrCodeUtil.generateQRCodeBytes(qrContent, 200, 200);
        } catch (Exception e) {
            throw new CustomException("二维码生成失败: " + e.getMessage());
        }

        // 存储QR码图片到文件系统或云存储
        String qrCodePath = fileStorageService.storeQRCode(qrCodeBytes,
                "activity_" + activityId + "_volunteer_" + volunteerId + ".png");

        Apply apply = new Apply();
        apply.setActivityId(activityId);
        apply.setVolunteerId(volunteerId);
        apply.setQrCodePath(qrCodePath); // 只存储路径
        apply.setStatus("pending");

        applyMapper.insert(apply);
    }

    @Override
    public void approveApplication(Integer activityId, String volunteerId) {
        Apply apply = applyMapper.findByActivityAndVolunteer(activityId, volunteerId);
        if (apply == null) {
            throw new CustomException("未找到该报名记录");
        }

        if ("approved".equals(apply.getStatus())) {
            throw new CustomException("该申请已通过审核");
        }

        // 生成二维码逻辑
        String qrContent = generateQRContent(activityId, volunteerId);
        String qrCodePath;
        try {
            qrCodePath = fileStorageService.storeQRCode(
                    qrCodeUtil.generateQRCodeBytes(qrContent, 200, 200),
                    "qr_activity_" + activityId + "_volunteer_" + volunteerId + ".png"
            );
        } catch (Exception e) {
            throw new CustomException("生成QR码失败: " + e.getMessage());
        }

        apply.setStatus("approved");
        apply.setApplyTime(new Date());
        apply.setQrCodePath(qrCodePath);
        applyMapper.update(apply);

        // 发送通知给志愿者
        try {
            notificationService.sendApprovalNotification(volunteerId, activityId);
        } catch (Exception e) {
            logger.error("发送通知失败", e);
        }
    }

    @Override
    public String generateQRContent(Integer activityId, String volunteerId) {
        return String.format("ACTIVITY:%d|VOLUNTEER:%s|%s",
                activityId,
                volunteerId,
                UUID.randomUUID().toString());
    }

    @Override
    public void rejectApplication(Integer activityId, String volunteerId) {
        Apply apply = applyMapper.findByActivityAndVolunteer(activityId, volunteerId);
        if (apply == null) {
            throw new CustomException("未找到该报名记录");
        }
        if ("rejected".equals(apply.getStatus())) {
            throw new CustomException("该申请已拒绝");
        }

        apply.setStatus("rejected");
        apply.setApplyTime(new Date());
        applyMapper.update(apply);

        // 发送通知给志愿者
        notificationService.sendRejectionNotification(volunteerId, activityId);
    }

    @Override
    public boolean checkActivityLimit(String volunteerId) {
        int count = applyMapper.countVolundeerIdActivities(volunteerId);
        return count < 3;
    }

    @Override
    @Transactional
    public void update(Apply apply) {
        // 1. 验证记录是否存在
        Apply existingApply = applyMapper.findByActivityAndVolunteer(
                apply.getActivityId(),
                apply.getVolunteerId()
        );
        if (existingApply == null) {
            throw new CustomException("未找到对应的报名记录");
        }
        // 2. 只更新允许修改的字段（避免覆盖二维码等关键数据）
        if (apply.getStatus() != null) {
            existingApply.setStatus(apply.getStatus());
        }
        if (apply.getApplyTime() != null) {
            existingApply.setApplyTime(apply.getApplyTime());
        }

        // 3. 执行更新并获取更新后的记录
        applyMapper.update(existingApply);
    }

    @Override
    @Transactional
    public void deleteApplication(Integer activityId, String volunteerId) {
        Apply apply = applyMapper.findByActivityAndVolunteer(activityId, volunteerId);
        if (apply == null) {
            throw new CustomException("未找到该报名记录");
        }

        // 删除关联的二维码文件
        if (apply.getQrCodePath() != null) {
            fileStorageService.deleteFile(apply.getQrCodePath());
        }

        // 删除积分记录
        Points points = pointsMapper.findByVolunteerAndActivity(volunteerId, activityId);
        if (points != null) {
            pointsMapper.delete(points.getPointsId()); // 使用积分ID删除
        }

        applyMapper.delete(activityId, volunteerId);
    }


    @Override
    public PageResult<Apply> findAppliesWithPage(int pageNum, int pageSize) {
        return createPageResult(
                applyMapper.findAppliesWithPage(calculateOffset(pageNum, pageSize), pageSize),
                applyMapper.countApplies(),
                pageNum,
                pageSize
        );
    }

    @Override
    public PageResult<Apply> getApplicationsByVolunteerWithPage(String volunteerId, int pageNum, int pageSize) {
        return createPageResult(
                applyMapper.findByVolunteerIdWithPage(volunteerId, calculateOffset(pageNum, pageSize), pageSize),
                applyMapper.countByVolunteerId(volunteerId),
                pageNum,
                pageSize
        );
    }

    @Override
    public PageResult<Apply> getApplicationsByActivityWithPage(Integer activityId, int pageNum, int pageSize) {
        return createPageResult(
                applyMapper.findByActivityIdWithPage(activityId, calculateOffset(pageNum, pageSize), pageSize),
                applyMapper.countByActivityId(activityId),
                pageNum,
                pageSize
        );
    }

    @Override
    public PageResult<Apply> getApplicationsByStatusWithPage(String status, int pageNum, int pageSize) {
        return createPageResult(
                applyMapper.findByStatusWithPage(status, calculateOffset(pageNum, pageSize), pageSize),
                applyMapper.countByStatus(status),
                pageNum,
                pageSize
        );
    }

    @Override
    public PageResult<Apply> getApplicationByTimeWithPage(Date time, int pageNum, int pageSize) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date startTime = calendar.getTime();

        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date endTime = calendar.getTime();

        return createPageResult(
                applyMapper.findByTimeWithPage(startTime, endTime, calculateOffset(pageNum, pageSize), pageSize),
                applyMapper.countByTime(startTime, endTime),
                pageNum,
                pageSize
        );
    }

    private int calculateOffset(int pageNum, int pageSize) {
        return (pageNum - 1) * pageSize;
    }

    private PageResult<Apply> createPageResult(List<Apply> data, int total, int pageNum, int pageSize) {
        PageResult<Apply> result = new PageResult<>();
        result.setData(data);
        result.setTotal(total);
        result.setPageNum(pageNum);
        result.setPageSize(pageSize);
        result.setPages((int) Math.ceil((double) total / pageSize));
        return result;
    }
}
